<template>
  <div class="dashboard">
    <el-row :gutter="20">
      <!-- 用户信息列（响应式） -->
      <el-col :xs="24" :sm="24" :md="8" :lg="6">
        <el-card class="user-card">
          <div class="user-info">
            <div class="avatar-container">
              <el-avatar :size="80" :src="avatarUrl">
                {{ user?.username?.charAt(0).toUpperCase() }}
              </el-avatar>
              <el-button
                type="primary"
                size="small"
                circle
                class="avatar-upload-btn"
                @click="showAvatarUpload = true"
              >
                <el-icon><Camera /></el-icon>
              </el-button>
            </div>
            <h2>{{ user?.username }}</h2>
            <p>{{ user?.email }}</p>
            <el-tag v-if="user?.phone">{{ user.phone }}</el-tag>
          </div>
          <el-divider />
          <div class="user-stats">
            <div class="stat-item">
              <span class="stat-label">关注</span>
              <span class="stat-value">{{ user?.following_count || 0 }}</span>
            </div>
            <div class="stat-item">
              <span class="stat-label">粉丝</span>
              <span class="stat-value">{{ user?.followers_count || 0 }}</span>
            </div>
          </div>
        </el-card>

        <!-- 偏好设置卡片 -->
        <el-card class="preferences-card" style="margin-top: 20px">
          <template #header>
            <span>偏好设置</span>
            <el-button type="text" @click="showPreferencesDialog = true">编辑</el-button>
          </template>
          <div v-if="user?.preferences && Object.keys(user.preferences).length > 0">
            <el-tag v-for="cat in user.preferences.categories" :key="cat" style="margin: 5px">
              {{ getCategoryName(cat) }}
            </el-tag>
            <p v-if="user.preferences.budget">预算: ¥{{ user.preferences.budget }}</p>
          </div>
          <p v-else class="empty-text">暂无偏好设置</p>
        </el-card>

        <!-- 账户安全卡片 -->
        <el-card class="security-card" style="margin-top: 20px">
          <template #header>
            <span>账户安全</span>
          </template>
          <div style="display: flex; flex-direction: column; gap: 10px;">
            <el-button type="primary" @click="showPasswordDialog = true" style="width: 100%">
              修改密码
            </el-button>
            <el-button 
              v-if="!user?.email_verified" 
              type="warning" 
              @click="showEmailVerificationDialog = true" 
              style="width: 100%"
            >
              验证邮箱
            </el-button>
            <el-tag v-else type="success" style="width: 100%; text-align: center;">
              <el-icon><CircleCheck /></el-icon>
              邮箱已验证
            </el-tag>
            <el-button 
              v-if="!user?.phone_verified && user?.phone" 
              type="warning" 
              @click="showPhoneVerificationDialog = true" 
              style="width: 100%"
            >
              验证手机号
            </el-button>
            <el-tag v-else-if="user?.phone_verified" type="success" style="width: 100%; text-align: center;">
              <el-icon><CircleCheck /></el-icon>
              手机号已验证
            </el-tag>
          </div>
        </el-card>
      </el-col>

      <!-- 主要内容区域（响应式） -->
      <el-col :xs="24" :sm="24" :md="16" :lg="18">
        <!-- 推荐景点 -->
        <el-card class="recommendations-card">
          <template #header>
            <div style="display: flex; align-items: center; gap: 10px">
              <el-icon style="font-size: 20px;"><Star /></el-icon>
              <span>为您推荐</span>
            </div>
          </template>
          <div v-loading="recommendationsLoading">
            <el-row :gutter="20" v-if="recommendations.length > 0">
              <el-col :xs="24" :sm="12" :md="8" v-for="rec in recommendations" :key="rec.attraction.id">
                <el-card shadow="hover" class="recommendation-card">
                  <h3>{{ rec.attraction.name }}</h3>
                  <p class="recommendation-reason">{{ rec.reason }}</p>
                  <div class="recommendation-info">
                    <el-tag type="success">推荐度: {{ (rec.score * 100).toFixed(0) }}%</el-tag>
                    <span class="price">¥{{ rec.attraction.ticket_price }}</span>
                  </div>
                  <el-button type="primary" size="small" @click="viewAttraction(rec.attraction.id)">
                    查看详情
                  </el-button>
                </el-card>
              </el-col>
            </el-row>
            <el-empty v-else description="暂无推荐" />
          </div>
        </el-card>

        <!-- 通知历史 -->
        <el-card class="notification-card" style="margin-top: 20px">
          <template #header>
            <div style="display: flex; justify-content: space-between; align-items: center">
              <div style="display: flex; align-items: center; gap: 10px">
                <el-icon style="font-size: 20px;"><Bell /></el-icon>
                <span>
                  通知历史
                  <el-badge v-if="unreadNotificationCount > 0" :value="unreadNotificationCount" class="notification-badge" />
                </span>
              </div>
              <div>
                <el-button v-if="unreadNotificationCount > 0" size="small" @click="markAllNotificationsAsRead" type="primary" plain>
                  全部已读
                </el-button>
                <el-button size="small" @click="showNotificationHistory = true" type="default">
                  查看全部
                </el-button>
              </div>
            </div>
          </template>
          <div v-loading="notificationsLoading">
            <div v-if="notificationHistory.length > 0" class="notification-list">
              <div
                v-for="notification in notificationHistory.slice(0, 5)"
                :key="notification.id"
                class="notification-item"
                :class="{ 'unread': !notification.read }"
                @click="markNotificationAsRead(notification.id)"
              >
                <div class="notification-content">
                  <div class="notification-header">
                    <strong>{{ notification.title }}</strong>
                    <el-tag v-if="!notification.read" type="danger" size="small">未读</el-tag>
                  </div>
                  <p class="notification-body">{{ notification.body }}</p>
                  <span class="notification-time">{{ formatNotificationTime(notification.timestamp) }}</span>
                </div>
              </div>
            </div>
            <el-empty v-else description="暂无通知" :image-size="80" />
          </div>
        </el-card>

        <!-- 我的行程 -->
        <el-card class="itineraries-card" style="margin-top: 20px">
          <template #header>
            <div style="display: flex; justify-content: space-between; align-items: center">
              <div style="display: flex; align-items: center; gap: 10px">
                <el-icon style="font-size: 20px;"><Calendar /></el-icon>
                <span>我的行程</span>
              </div>
              <el-button type="primary" @click="$router.push('/itineraries')" class="create-button">
                创建行程
              </el-button>
            </div>
          </template>
          <div v-loading="itinerariesLoading">
            <el-timeline v-if="itineraries.length > 0">
              <el-timeline-item
                v-for="itinerary in itineraries"
                :key="itinerary.id"
                :timestamp="itinerary.start_date"
                placement="top"
              >
                <el-card>
                  <h4>{{ itinerary.title }}</h4>
                  <p>{{ itinerary.start_date }} 至 {{ itinerary.end_date }}</p>
                  <p>预算: ¥{{ itinerary.total_budget }}</p>
                </el-card>
              </el-timeline-item>
            </el-timeline>
            <el-empty v-else description="暂无行程" />
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 头像上传对话框 -->
    <el-dialog v-model="showAvatarUpload" title="上传头像" width="400px">
      <ImageUpload
        upload-type="avatar"
        :limit="1"
        :multiple="false"
        v-model="avatarList"
        @success="handleAvatarSuccess"
      />
    </el-dialog>

    <!-- 邮箱验证对话框 -->
    <el-dialog v-model="showEmailVerificationDialog" title="验证邮箱" width="500px" @close="resetEmailVerification">
      <el-form :model="emailVerificationForm" :rules="emailVerificationRules" ref="emailVerificationFormRef" label-width="100px">
        <el-form-item label="邮箱地址" prop="email">
          <el-input
            v-model="emailVerificationForm.email"
            placeholder="请输入邮箱地址"
            :disabled="emailVerificationForm.verificationCodeSent"
          >
            <template #append>
              <el-button 
                @click="sendEmailVerificationCode" 
                :loading="sendingEmailCode"
                :disabled="emailVerificationForm.verificationCodeSent"
              >
                {{ emailVerificationForm.verificationCodeSent ? '已发送' : '发送验证码' }}
              </el-button>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="验证码" prop="verificationCode" v-if="emailVerificationForm.verificationCodeSent">
          <el-input
            v-model="emailVerificationForm.verificationCode"
            placeholder="请输入6位验证码"
            maxlength="6"
          />
          <div style="margin-top: 5px; font-size: 12px; color: #909399;">
            验证码已发送到您的邮箱，10分钟内有效
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showEmailVerificationDialog = false">取消</el-button>
        <el-button 
          type="primary" 
          @click="verifyEmail" 
          :loading="verifyingEmail"
          :disabled="!emailVerificationForm.verificationCodeSent"
        >
          验证
        </el-button>
      </template>
    </el-dialog>

    <!-- 手机验证对话框 -->
    <el-dialog v-model="showPhoneVerificationDialog" title="验证手机号" width="500px" @close="resetPhoneVerification">
      <el-form :model="phoneVerificationForm" :rules="phoneVerificationRules" ref="phoneVerificationFormRef" label-width="100px">
        <el-form-item label="手机号" prop="phone">
          <el-input
            v-model="phoneVerificationForm.phone"
            placeholder="请输入手机号"
            :disabled="phoneVerificationForm.verificationCodeSent"
            :value="user?.phone || ''"
          >
            <template #append>
              <el-button 
                @click="sendPhoneVerificationCode" 
                :loading="sendingPhoneCode"
                :disabled="phoneVerificationForm.verificationCodeSent"
              >
                {{ phoneVerificationForm.verificationCodeSent ? '已发送' : '发送验证码' }}
              </el-button>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="验证码" prop="verificationCode" v-if="phoneVerificationForm.verificationCodeSent">
          <el-input
            v-model="phoneVerificationForm.verificationCode"
            placeholder="请输入6位验证码"
            maxlength="6"
          />
          <div style="margin-top: 5px; font-size: 12px; color: #909399;">
            验证码已发送到您的手机，5分钟内有效
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showPhoneVerificationDialog = false">取消</el-button>
        <el-button 
          type="primary" 
          @click="verifyPhone" 
          :loading="verifyingPhone"
          :disabled="!phoneVerificationForm.verificationCodeSent"
        >
          验证
        </el-button>
      </template>
    </el-dialog>

    <!-- 偏好设置对话框 -->
    <el-dialog v-model="showPreferencesDialog" title="偏好设置" width="500px">
      <el-form :model="preferencesForm" label-width="100px">
        <el-form-item label="偏好分类">
          <el-checkbox-group v-model="preferencesForm.categories">
            <el-checkbox label="cultural">文化古迹</el-checkbox>
            <el-checkbox label="natural">自然风光</el-checkbox>
            <el-checkbox label="modern">现代建筑</el-checkbox>
            <el-checkbox label="food">美食购物</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
        <el-form-item label="预算">
          <el-input-number v-model="preferencesForm.budget" :min="0" :max="10000" />
        </el-form-item>
        <el-form-item label="交通方式">
          <el-radio-group v-model="preferencesForm.transport_mode">
            <el-radio label="walking">步行</el-radio>
            <el-radio label="driving">自驾</el-radio>
            <el-radio label="transit">公共交通</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showPreferencesDialog = false">取消</el-button>
        <el-button type="primary" @click="savePreferences">保存</el-button>
      </template>
    </el-dialog>

    <!-- 修改密码对话框 -->
    <el-dialog v-model="showPasswordDialog" title="修改密码" width="500px">
      <el-form :model="passwordForm" :rules="passwordRules" ref="passwordFormRef" label-width="120px">
        <el-form-item label="原密码" prop="oldPassword">
          <el-input
            v-model="passwordForm.oldPassword"
            type="password"
            placeholder="请输入原密码"
            show-password
          />
        </el-form-item>
        <el-form-item label="新密码" prop="newPassword">
          <el-input
            v-model="passwordForm.newPassword"
            type="password"
            placeholder="请输入新密码（至少6个字符）"
            show-password
          />
        </el-form-item>
        <el-form-item label="确认新密码" prop="newPasswordConfirm">
          <el-input
            v-model="passwordForm.newPasswordConfirm"
            type="password"
            placeholder="请再次输入新密码"
            show-password
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showPasswordDialog = false">取消</el-button>
        <el-button type="primary" @click="changePassword" :loading="changingPassword">确定</el-button>
      </template>
    </el-dialog>

    <!-- 通知历史对话框 -->
    <el-dialog v-model="showNotificationHistory" title="通知历史" width="600px">
      <div class="notification-history-dialog">
        <div style="margin-bottom: 15px; display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;">
          <div style="display: flex; align-items: center; gap: 12px;">
            <span>共 {{ useServerNotifications ? notificationsTotal : notificationHistory.length }} 条通知</span>
            <el-switch v-model="notificationFilterOnlyUnread" active-text="仅未读" @change="applyNotificationFilter" />
            <el-select v-model="notificationFilterType" placeholder="类型" clearable style="width: 140px;" @change="applyNotificationFilter">
              <el-option label="全部" value="" />
              <el-option label="提醒" value="reminder" />
              <el-option label="普通" value="general" />
            </el-select>
            <el-date-picker
              v-model="notificationFilterDateRange"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              style="width: 280px;"
              @change="applyNotificationFilter"
            />
            <el-select v-model="notificationFilterOrdering" placeholder="排序" style="width: 140px;" @change="applyNotificationFilter">
              <el-option label="最新优先" value="-created_at" />
              <el-option label="最早优先" value="created_at" />
            </el-select>
          </div>
          <div>
            <el-button v-if="unreadNotificationCount > 0" size="small" @click="markAllNotificationsAsRead">
              全部已读
            </el-button>
            <el-button size="小" @click="clearNotifications">
              清空历史
            </el-button>
          </div>
        </div>
        <div class="notification-history-list">
          <div
            v-for="notification in notificationHistory"
            :key="notification.id"
            class="notification-history-item"
            :class="{ 'unread': !notification.read }"
            @click="markNotificationAsRead(notification.id)"
          >
            <div class="notification-history-content">
              <div class="notification-history-header">
                <strong>{{ notification.title }}</strong>
                <el-tag v-if="!notification.read" type="danger" size="small">未读</el-tag>
              </div>
              <p class="notification-history-body">{{ notification.body }}</p>
              <span class="notification-history-time">{{ formatNotificationTime(notification.timestamp) }}</span>
            </div>
          </div>
          <el-empty v-if="notificationHistory.length === 0" description="暂无通知历史" />
          <div v-if="useServerNotifications && hasMoreNotifications" style="text-align: center; margin-top: 10px;">
            <el-button size="small" @click="loadMoreNotifications">加载更多</el-button>
          </div>
          <div v-if="useServerNotifications" style="margin-top: 10px; display: flex; justify-content: center;">
            <el-pagination
              background
              layout="prev, pager, next"
              :total="notificationsTotal"
              :current-page="notificationsPage"
              :page-size="notificationsPageSize"
              @current-change="onNotificationsPageChange"
            />
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { ElMessage } from 'element-plus'
import { Camera, Bell, Star, Calendar, CircleCheck } from '@element-plus/icons-vue'
import TravelAPI from '../api/travel'
import ImageUpload from '../components/ImageUpload.vue'
import notificationManager from '../utils/notification'
import logger from '../utils/logger'
import { getApiBaseUrl } from '../utils/apiConfig'

export default {
  name: 'Dashboard',
  components: {
    ImageUpload,
    Camera
  },
  setup() {
    const router = useRouter()
    const store = useStore()
    const recommendationsLoading = ref(false)
    const itinerariesLoading = ref(false)
    const notificationsLoading = ref(false)
    const showPreferencesDialog = ref(false)
    const showAvatarUpload = ref(false)
    const showPasswordDialog = ref(false)
    const showNotificationHistory = ref(false)
    const changingPassword = ref(false)
    const showEmailVerificationDialog = ref(false)
    const showPhoneVerificationDialog = ref(false)
    const sendingEmailCode = ref(false)
    const sendingPhoneCode = ref(false)
    const verifyingEmail = ref(false)
    const verifyingPhone = ref(false)
    const emailVerificationFormRef = ref(null)
    const phoneVerificationFormRef = ref(null)
    const recommendations = ref([])
    const itineraries = ref([])
    const avatarList = ref([])
    const passwordFormRef = ref(null)
    const notificationHistory = ref([])
    
    const notificationsPage = ref(1)
    const notificationsPageSize = ref(50)
    const notificationsTotal = ref(0)
    const useServerNotifications = ref(false)
    const notificationFilterOnlyUnread = ref(false)
    const notificationFilterType = ref('')
    const notificationFilterDateRange = ref([])
    const notificationFilterOrdering = ref('-created_at')
    
    const passwordForm = ref({
      oldPassword: '',
      newPassword: '',
      newPasswordConfirm: ''
    })
    
    const emailVerificationForm = ref({
      email: '',
      verificationCode: '',
      verificationCodeSent: false
    })
    
    const phoneVerificationForm = ref({
      phone: '',
      verificationCode: '',
      verificationCodeSent: false
    })
    
    const emailVerificationRules = {
      email: [
        { required: true, message: '请输入邮箱地址', trigger: 'blur' },
        { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
      ],
      verificationCode: [
        { required: true, message: '请输入验证码', trigger: 'blur' },
        { len: 6, message: '验证码为6位数字', trigger: 'blur' }
      ]
    }
    
    const phoneVerificationRules = {
      phone: [
        { required: true, message: '请输入手机号', trigger: 'blur' },
        { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
      ],
      verificationCode: [
        { required: true, message: '请输入验证码', trigger: 'blur' },
        { len: 6, message: '验证码为6位数字', trigger: 'blur' }
      ]
    }
    
    const passwordRules = {
      oldPassword: [
        { required: true, message: '请输入原密码', trigger: 'blur' }
      ],
      newPassword: [
        { required: true, message: '请输入新密码', trigger: 'blur' },
        { min: 6, message: '密码长度不能少于6个字符', trigger: 'blur' }
      ],
      newPasswordConfirm: [
        { required: true, message: '请确认新密码', trigger: 'blur' },
        {
          validator: (rule, value, callback) => {
            if (value !== passwordForm.value.newPassword) {
              callback(new Error('两次密码输入不一致'))
            } else {
              callback()
            }
          },
          trigger: 'blur'
        }
      ]
    }

    const user = computed(() => store.getters.currentUser)
    
    const avatarUrl = computed(() => {
      if (avatarList.value.length > 0) {
        return avatarList.value[0].url
      }
      if (user.value?.avatar) {
        // 如果是相对路径，添加API基础URL
        if (user.value.avatar.startsWith('/media/')) {
          const baseUrl = getApiBaseUrl()
          return `${baseUrl}${user.value.avatar}`
        }
        return user.value.avatar
      }
      return null
    })

    const preferencesForm = ref({
      categories: [],
      budget: 1000,
      transport_mode: 'walking'
    })

    const getCategoryName = (category) => {
      const names = {
        cultural: '文化古迹',
        natural: '自然风光',
        modern: '现代建筑',
        food: '美食购物'
      }
      return names[category] || category
    }

    const fetchRecommendations = async () => {
      recommendationsLoading.value = true
      try {
        const response = await TravelAPI.getRecommendations({
          user_id: user.value?.id,
          limit: 6
        })
        recommendations.value = response.recommendations || []
      } catch (error) {
        logger.error('获取推荐失败:', error)
        // 推荐失败不显示错误提示，避免影响用户体验
        // 只在控制台记录错误
      } finally {
        recommendationsLoading.value = false
      }
    }

    const fetchItineraries = async () => {
      itinerariesLoading.value = true
      try {
        const response = await TravelAPI.getItineraries()
        itineraries.value = response.results || response || []
      } catch (error) {
        logger.error('获取行程失败:', error)
        // 行程获取失败不显示错误提示，避免影响用户体验
      } finally {
        itinerariesLoading.value = false
      }
    }

    const savePreferences = async () => {
      try {
        await TravelAPI.updatePreferences(user.value.id, preferencesForm.value)
        await store.dispatch('fetchUserInfo')
        showPreferencesDialog.value = false
        ElMessage.success('偏好设置已保存')
        fetchRecommendations()
      } catch (error) {
        logger.error('保存偏好设置失败:', error)
        let errorMessage = '保存失败'
        if (error.response) {
          const status = error.response.status
          if (status === 400) {
            errorMessage = error.response.data?.error || error.response.data?.detail || '请求参数错误'
          } else if (status === 401) {
            errorMessage = '登录已过期，请重新登录'
          } else if (status === 403) {
            errorMessage = '没有权限修改偏好设置'
          } else if (error.response.data?.error) {
            errorMessage = error.response.data.error
          } else if (error.response.data?.detail) {
            errorMessage = error.response.data.detail
          }
        } else if (error.message) {
          if (error.message.includes('timeout') || error.message.includes('Network Error')) {
            errorMessage = '网络错误，请检查网络连接'
          }
        }
        ElMessage.error(errorMessage)
      }
    }

    const viewAttraction = (id) => {
      router.push(`/attractions?id=${id}`)
    }
    
    // eslint-disable-next-line no-unused-vars
    const handleAvatarSuccess = async (response) => {
      // 更新用户信息
      await store.dispatch('fetchUserInfo')
      showAvatarUpload.value = false
      ElMessage.success('头像上传成功')
    }
    
    const changePassword = async () => {
      if (!passwordFormRef.value) return
      
      try {
        await passwordFormRef.value.validate()
        
        if (!user.value?.id) {
          ElMessage.error('用户信息不存在')
          return
        }
        
        changingPassword.value = true
        
        await TravelAPI.changePassword(
          user.value.id,
          passwordForm.value.oldPassword,
          passwordForm.value.newPassword,
          passwordForm.value.newPasswordConfirm
        )
        
        ElMessage.success('密码修改成功，请重新登录')
        showPasswordDialog.value = false
        passwordForm.value = {
          oldPassword: '',
          newPassword: '',
          newPasswordConfirm: ''
        }
        
        // 延迟跳转到登录页
        setTimeout(() => {
          store.dispatch('logout')
          router.push('/login')
        }, 1500)
      } catch (error) {
        logger.error('修改密码失败:', error)
        let errorMessage = '修改密码失败'
        if (error.response) {
          const status = error.response.status
          if (status === 400) {
            errorMessage = error.response.data?.error || '请求参数错误'
          } else if (status === 403) {
            errorMessage = '没有权限修改密码'
          } else if (error.response.data?.error) {
            errorMessage = error.response.data.error
          } else if (error.response.data?.detail) {
            errorMessage = error.response.data.detail
          }
        } else if (error.message) {
          errorMessage = error.message
        }
        ElMessage.error(errorMessage)
      } finally {
        changingPassword.value = false
      }
    }

    const sendEmailVerificationCode = async () => {
      if (!emailVerificationFormRef.value) return
      
      try {
        await emailVerificationFormRef.value.validateField('email')
        
        if (!emailVerificationForm.value.email) {
          ElMessage.error('请输入邮箱地址')
          return
        }
        
        sendingEmailCode.value = true
        
        await TravelAPI.sendEmailVerification(emailVerificationForm.value.email)
        
        emailVerificationForm.value.verificationCodeSent = true
        ElMessage.success('验证码已发送到您的邮箱，请查收')
      } catch (error) {
        logger.error('发送邮箱验证码失败:', error)
        let errorMessage = '发送验证码失败'
        if (error.response) {
          if (error.response.data?.error) {
            errorMessage = error.response.data.error
          } else if (error.response.data?.detail) {
            errorMessage = error.response.data.detail
          }
        }
        ElMessage.error(errorMessage)
      } finally {
        sendingEmailCode.value = false
      }
    }

    const verifyEmail = async () => {
      if (!emailVerificationFormRef.value) return
      
      try {
        await emailVerificationFormRef.value.validate()
        
        verifyingEmail.value = true
        
        await TravelAPI.verifyEmail(
          emailVerificationForm.value.email,
          emailVerificationForm.value.verificationCode
        )
        
        ElMessage.success('邮箱验证成功')
        showEmailVerificationDialog.value = false
        resetEmailVerification()
        
        // 刷新用户信息
        await store.dispatch('fetchUserInfo')
      } catch (error) {
        logger.error('验证邮箱失败:', error)
        let errorMessage = '验证失败'
        if (error.response) {
          if (error.response.data?.error) {
            errorMessage = error.response.data.error
          } else if (error.response.data?.detail) {
            errorMessage = error.response.data.detail
          }
        }
        ElMessage.error(errorMessage)
      } finally {
        verifyingEmail.value = false
      }
    }

    const resetEmailVerification = () => {
      emailVerificationForm.value = {
        email: '',
        verificationCode: '',
        verificationCodeSent: false
      }
      if (emailVerificationFormRef.value) {
        emailVerificationFormRef.value.clearValidate()
      }
    }

    const sendPhoneVerificationCode = async () => {
      if (!phoneVerificationFormRef.value) return
      
      try {
        await phoneVerificationFormRef.value.validateField('phone')
        
        if (!phoneVerificationForm.value.phone) {
          ElMessage.error('请输入手机号')
          return
        }
        
        sendingPhoneCode.value = true
        
        const response = await TravelAPI.sendPhoneVerification(phoneVerificationForm.value.phone)
        
        phoneVerificationForm.value.verificationCodeSent = true
        
        // 开发环境可能返回验证码
        if (response.verification_code && process.env.NODE_ENV === 'development') {
          ElMessage.success(`验证码已发送（开发环境）：${response.verification_code}`)
        } else {
          ElMessage.success('验证码已发送到您的手机，请查收')
        }
      } catch (error) {
        logger.error('发送手机验证码失败:', error)
        let errorMessage = '发送验证码失败'
        if (error.response) {
          if (error.response.data?.error) {
            errorMessage = error.response.data.error
          } else if (error.response.data?.detail) {
            errorMessage = error.response.data.detail
          }
        }
        ElMessage.error(errorMessage)
      } finally {
        sendingPhoneCode.value = false
      }
    }

    const verifyPhone = async () => {
      if (!phoneVerificationFormRef.value) return
      
      try {
        await phoneVerificationFormRef.value.validate()
        
        verifyingPhone.value = true
        
        await TravelAPI.verifyPhone(
          phoneVerificationForm.value.phone,
          phoneVerificationForm.value.verificationCode
        )
        
        ElMessage.success('手机号验证成功')
        showPhoneVerificationDialog.value = false
        resetPhoneVerification()
        
        // 刷新用户信息
        await store.dispatch('fetchUserInfo')
      } catch (error) {
        logger.error('验证手机号失败:', error)
        let errorMessage = '验证失败'
        if (error.response) {
          if (error.response.data?.error) {
            errorMessage = error.response.data.error
          } else if (error.response.data?.detail) {
            errorMessage = error.response.data.detail
          }
        }
        ElMessage.error(errorMessage)
      } finally {
        verifyingPhone.value = false
      }
    }

    const resetPhoneVerification = () => {
      phoneVerificationForm.value = {
        phone: user.value?.phone || '',
        verificationCode: '',
        verificationCodeSent: false
      }
      if (phoneVerificationFormRef.value) {
        phoneVerificationFormRef.value.clearValidate()
      }
    }

    onMounted(async () => {
      // 检查是否有token
      const token = store.state.token || localStorage.getItem('token')
      if (!token) {
        ElMessage.warning('请先登录')
        router.push('/login')
        return
      }
      
      // 如果没有用户信息，先获取用户信息
      if (!user.value) {
        try {
          await store.dispatch('fetchUserInfo')
        } catch (error) {
          logger.error('获取用户信息失败:', error)
          // 如果获取失败，可能是token无效，清除token并跳转到登录页
          if (error.response && error.response.status === 401) {
            store.dispatch('logout')
            ElMessage.error('身份认证失败，请重新登录')
            router.push('/login')
            return
          }
        }
      }
      
      // 设置偏好表单
      if (user.value?.preferences) {
        preferencesForm.value = { ...user.value.preferences }
      }
      
      // 设置头像列表
      if (user.value?.avatar) {
        avatarList.value = [{
          id: 'avatar',
          url: user.value.avatar.startsWith('/media/') 
            ? `${getApiBaseUrl()}${user.value.avatar}`
            : user.value.avatar,
          name: 'avatar.jpg'
        }]
      }
      
      // 获取推荐和行程（这些API可能需要认证，但失败不影响页面显示）
      fetchRecommendations()
      fetchItineraries()
      
      // 请求通知权限
      notificationManager.requestPermission().then(granted => {
        if (granted) {
          logger.info('通知权限已授予')
        }
      })
      
      // 检查即将到来的提醒
      checkUpcomingReminders()
      
      // 每30秒检查一次即将到来的提醒（更频繁的检查）
      reminderCheckInterval.value = setInterval(checkUpcomingReminders, 30 * 1000)

      // 加载通知历史（优先服务端，失败回退本地）
      await loadNotificationHistory()
    })

    const reminderCheckInterval = ref(null)

    // 加载通知历史
    const loadNotificationHistory = async () => {
      try {
        const data = await TravelAPI.getNotifications({ page: notificationsPage.value, page_size: notificationsPageSize.value })
        const results = data.results || []
        notificationsTotal.value = data.count ?? results.length
        if (notificationsPage.value === 1) {
          notificationHistory.value = results
        } else {
          notificationHistory.value = notificationHistory.value.concat(results)
        }
        useServerNotifications.value = true
      } catch (error) {
        useServerNotifications.value = false
        const local = notificationManager.getHistory(notificationsPageSize.value)
        notificationsTotal.value = local.length
        notificationHistory.value = local
      }
    }

    const hasMoreNotifications = computed(() => notificationHistory.value.length < notificationsTotal.value)

    const loadMoreNotifications = async () => {
      if (!hasMoreNotifications.value) return
      notificationsPage.value += 1
      await loadNotificationHistory()
    }

    const applyNotificationFilter = async () => {
      notificationsPage.value = 1
      await loadNotificationHistory()
    }

    const onNotificationsPageChange = async (page) => {
      notificationsPage.value = page
      await loadNotificationHistory()
    }

    // 未读通知数量
    const unreadNotificationCount = computed(() => {
      if (useServerNotifications.value) {
        return (notificationHistory.value || []).filter(n => !n.read).length
      }
      return notificationManager.getUnreadCount()
    })

    // 标记通知为已读
    const markNotificationAsRead = async (notificationId) => {
      if (useServerNotifications.value) {
        try {
          await TravelAPI.markNotificationRead(notificationId)
        } catch (error) {
          useServerNotifications.value = false
          notificationManager.markAsRead(notificationId)
        }
        await loadNotificationHistory()
      } else {
        notificationManager.markAsRead(notificationId)
        loadNotificationHistory()
      }
    }

    // 标记所有通知为已读
    const markAllNotificationsAsRead = async () => {
      if (useServerNotifications.value) {
        try {
          await TravelAPI.markAllNotificationsRead()
          await loadNotificationHistory()
        } catch (error) {
          useServerNotifications.value = false
          notificationManager.markAllAsRead()
          loadNotificationHistory()
        }
      } else {
        notificationManager.markAllAsRead()
        loadNotificationHistory()
      }
      ElMessage.success('已标记所有通知为已读')
    }

    const clearNotifications = async () => {
      if (useServerNotifications.value) {
        try {
          await TravelAPI.clearNotifications()
          await loadNotificationHistory()
          ElMessage.success('已清空通知历史')
          return
        } catch (error) {
          useServerNotifications.value = false
        }
      }
      notificationManager.clearHistory()
      await loadNotificationHistory()
      ElMessage.success('已清空通知历史')
    }

    // 格式化通知时间
    const formatNotificationTime = (timestamp) => {
      if (!timestamp) return ''
      const date = new Date(timestamp)
      const now = new Date()
      const diff = now - date
      const minutes = Math.floor(diff / 60000)
      const hours = Math.floor(diff / 3600000)
      const days = Math.floor(diff / 86400000)

      if (minutes < 1) return '刚刚'
      if (minutes < 60) return `${minutes}分钟前`
      if (hours < 24) return `${hours}小时前`
      if (days < 7) return `${days}天前`
      
      return date.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
      })
    }

    const checkUpcomingReminders = async () => {
      try {
        const response = await TravelAPI.getUpcomingReminders()
        const upcomingReminders = response.results || response || []
        
        // 显示通知
        for (const reminder of upcomingReminders) {
          const reminderKey = `reminder_shown_${reminder.id}`
          if (!localStorage.getItem(reminderKey)) {
            await notificationManager.showReminderNotification(reminder)
            localStorage.setItem(reminderKey, 'true')
            setTimeout(() => {
              localStorage.removeItem(reminderKey)
            }, 5 * 60 * 1000)
            // 更新通知历史
            loadNotificationHistory()
          }
        }
      } catch (error) {
        // 静默失败，不影响用户体验，但记录日志
        import('../utils/logger').then(({ logger }) => {
          logger.error('检查即将到来的提醒失败:', error)
        })
      }
    }

    onUnmounted(() => {
      if (reminderCheckInterval.value) {
        clearInterval(reminderCheckInterval.value)
        reminderCheckInterval.value = null
      }
    })

    return {
      user,
      recommendations,
      recommendationsLoading,
      itineraries,
      itinerariesLoading,
      showPreferencesDialog,
      showPasswordDialog,
      passwordForm,
      passwordRules,
      passwordFormRef,
      changePassword,
      changingPassword,
      showAvatarUpload,
      preferencesForm,
      avatarList,
      avatarUrl,
      getCategoryName,
      savePreferences,
      viewAttraction,
      handleAvatarSuccess,
      checkUpcomingReminders,
      notificationHistory,
      useServerNotifications,
      notificationsPage,
      notificationsPageSize,
      notificationsTotal,
      hasMoreNotifications,
      loadMoreNotifications,
      onNotificationsPageChange,
      notificationFilterOnlyUnread,
      notificationFilterType,
      notificationFilterDateRange,
      notificationFilterOrdering,
      applyNotificationFilter,
      unreadNotificationCount,
      markNotificationAsRead,
      markAllNotificationsAsRead,
      formatNotificationTime,
      clearNotifications,
      showNotificationHistory,
      notificationsLoading,
      Bell,
      Star,
      Calendar,
      CircleCheck,
      showEmailVerificationDialog,
      showPhoneVerificationDialog,
      emailVerificationForm,
      phoneVerificationForm,
      emailVerificationRules,
      phoneVerificationRules,
      emailVerificationFormRef,
      phoneVerificationFormRef,
      sendingEmailCode,
      sendingPhoneCode,
      verifyingEmail,
      verifyingPhone,
      sendEmailVerificationCode,
      verifyEmail,
      resetEmailVerification,
      sendPhoneVerificationCode,
      verifyPhone,
      resetPhoneVerification
    }
  }
}
</script>

<style scoped>
.dashboard {
  max-width: 1400px;
  margin: 0 auto;
  padding: 20px;
  /* 南昌旅游特色：天空蓝渐变背景 */
  background: linear-gradient(135deg, #E3F2FD 0%, #BBDEFB 50%, #90CAF9 100%);
  min-height: 100vh;
  animation: fadeIn 0.5s ease-in;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.user-card,
.preferences-card,
.security-card {
  border-radius: 16px;
  border: 1px solid rgba(200, 16, 46, 0.12);
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  background: linear-gradient(135deg, rgba(255,255,255,0.98) 0%, rgba(227,242,253,0.85) 100%);
  backdrop-filter: blur(12px);
  box-shadow: 0 4px 20px rgba(200, 16, 46, 0.08), 0 1px 3px rgba(0, 0, 0, 0.05);
  position: relative;
  overflow: hidden;
}

.user-card::before,
.preferences-card::before,
.security-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, #C8102E 0%, #D4AF37 50%, #1E88E5 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.user-card:hover::before,
.preferences-card:hover::before,
.security-card:hover::before {
  opacity: 1;
}

.user-card:hover,
.preferences-card:hover,
.security-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 32px rgba(200, 16, 46, 0.15), 0 4px 8px rgba(0, 0, 0, 0.1);
  border-color: rgba(212, 175, 55, 0.4);
}

.user-card {
  text-align: center;
}

.user-info {
  padding: 30px 20px;
}

.user-info h2 {
  margin: 20px 0 8px 0;
  font-size: 24px;
  font-weight: 700;
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  transition: all 0.3s ease;
}

.user-info p {
  margin: 8px 0;
  color: #909399;
  font-size: 14px;
}

.avatar-container {
  position: relative;
  display: inline-block;
  margin-bottom: 20px;
}

.avatar-upload-btn {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 3px solid white;
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  box-shadow: 0 4px 12px rgba(200, 16, 46, 0.3);
  transition: all 0.3s ease;
}

.avatar-upload-btn:hover {
  transform: scale(1.1);
  box-shadow: 0 6px 16px rgba(200, 16, 46, 0.4);
}

.user-stats {
  display: flex;
  justify-content: space-around;
  padding: 20px 0;
}

.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.stat-label {
  font-size: 13px;
  color: #909399;
  margin-bottom: 8px;
}

.stat-value {
  font-size: 28px;
  font-weight: 700;
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  transition: all 0.3s ease;
}

.stat-item:hover .stat-value {
  transform: scale(1.15);
}

.preferences-card {
  text-align: left;
}

.preferences-card :deep(.el-card__header) {
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.notification-card,
.recommendations-card,
.itineraries-card {
  border-radius: 16px;
  border: 1px solid rgba(200, 16, 46, 0.12);
  background: linear-gradient(135deg, rgba(255,255,255,0.98) 0%, rgba(227,242,253,0.85) 100%);
  backdrop-filter: blur(12px);
  box-shadow: 0 4px 20px rgba(200, 16, 46, 0.08), 0 1px 3px rgba(0, 0, 0, 0.05);
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

.notification-card::before,
.recommendations-card::before,
.itineraries-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, #C8102E 0%, #D4AF37 50%, #1E88E5 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.notification-card:hover::before,
.recommendations-card:hover::before,
.itineraries-card:hover::before {
  opacity: 1;
}

.notification-card:hover,
.recommendations-card:hover,
.itineraries-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(200, 16, 46, 0.12), 0 2px 6px rgba(0, 0, 0, 0.08);
  border-color: rgba(212, 175, 55, 0.3);
}

.create-button {
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  border: none;
  font-weight: 600;
  transition: all 0.3s ease;
}

.create-button:hover {
  background: linear-gradient(135deg, #D4AF37 0%, #C8102E 100%);
  box-shadow: 0 4px 12px rgba(200, 16, 46, 0.3);
  transform: translateY(-2px);
}

.preferences-card :deep(.el-card__header) {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
}

.empty-text {
  color: #909399;
  text-align: center;
  padding: 30px;
  font-size: 14px;
}

.recommendation-card {
  margin-bottom: 20px;
  border-radius: 16px;
  border: 1px solid rgba(200, 16, 46, 0.12);
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  background: linear-gradient(135deg, rgba(255,255,255,0.98) 0%, rgba(227,242,253,0.85) 100%);
  backdrop-filter: blur(12px);
  box-shadow: 0 4px 20px rgba(200, 16, 46, 0.08), 0 1px 3px rgba(0, 0, 0, 0.05);
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.recommendation-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, #C8102E 0%, #D4AF37 50%, #1E88E5 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.recommendation-card:hover::before {
  opacity: 1;
}

.recommendation-card:hover {
  transform: translateY(-4px) scale(1.01);
  box-shadow: 0 12px 32px rgba(200, 16, 46, 0.15), 0 4px 8px rgba(0, 0, 0, 0.1);
  border-color: rgba(212, 175, 55, 0.4);
}

.recommendation-card h3 {
  margin: 0 0 12px 0;
  font-size: 18px;
  font-weight: 600;
  background: linear-gradient(135deg, #303133 0%, #606266 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  transition: all 0.3s ease;
}

.recommendation-card:hover h3 {
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.recommendation-reason {
  color: #606266;
  font-size: 14px;
  margin: 12px 0;
  line-height: 1.6;
  min-height: 40px;
}

.recommendation-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 15px 0;
  padding-top: 15px;
  border-top: 1px solid #f0f0f0;
}

.price {
  font-size: 22px;
  font-weight: 700;
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

:deep(.el-card__header) {
  font-size: 18px;
  font-weight: 600;
  background: linear-gradient(135deg, #C8102E 0%, #D4AF37 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  padding: 20px;
  border-bottom: 2px solid rgba(200, 16, 46, 0.1);
}

:deep(.el-descriptions__label) {
  font-weight: 600;
  color: #606266;
}

/* 通知历史样式 */
.notification-list {
  max-height: 400px;
  overflow-y: auto;
}

.notification-item {
  padding: 16px;
  margin-bottom: 12px;
  border-radius: 12px;
  border: 1px solid rgba(200, 16, 46, 0.1);
  background: linear-gradient(135deg, rgba(255,255,255,0.95) 0%, rgba(227,242,253,0.7) 100%);
  backdrop-filter: blur(8px);
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

.notification-item::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: linear-gradient(180deg, #C8102E 0%, #D4AF37 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.notification-item:hover {
  transform: translateX(4px);
  box-shadow: 0 4px 16px rgba(200, 16, 46, 0.12);
  border-color: rgba(212, 175, 55, 0.3);
}

.notification-item:hover::before {
  opacity: 1;
}

.notification-item.unread {
  background: linear-gradient(135deg, rgba(200, 16, 46, 0.05) 0%, rgba(212, 175, 55, 0.05) 100%);
  border-color: rgba(200, 16, 46, 0.2);
}

.notification-item.unread::before {
  opacity: 1;
  width: 4px;
}

.notification-content {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.notification-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.notification-header strong {
  color: #303133;
  font-size: 14px;
}

.notification-body {
  color: #606266;
  font-size: 13px;
  margin: 0;
  line-height: 1.5;
}

.notification-time {
  color: #909399;
  font-size: 12px;
}

.notification-badge {
  margin-left: 8px;
}

/* 通知历史对话框样式 */
.notification-history-list {
  max-height: 500px;
  overflow-y: auto;
}

.notification-history-item {
  padding: 15px;
  margin-bottom: 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.8);
  cursor: pointer;
  transition: all 0.3s ease;
  border-left: 3px solid transparent;
}

.notification-history-item:hover {
  background: rgba(255, 255, 255, 0.95);
  transform: translateX(4px);
}

.notification-history-item.unread {
  border-left-color: #C8102E;
  background: rgba(200, 16, 46, 0.05);
}

.notification-history-content {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.notification-history-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.notification-history-header strong {
  color: #303133;
  font-size: 15px;
}

.notification-history-body {
  color: #606266;
  font-size: 14px;
  margin: 0;
  line-height: 1.6;
}

.notification-history-time {
  color: #909399;
  font-size: 12px;
}

/* 响应式设计 */
@media (max-width: 1200px) {
  .dashboard {
    padding: 15px;
  }

  .user-card,
  .preferences-card,
  .security-card {
    margin-bottom: 15px;
  }
}

/* 平板设备 (768px - 991px) */
@media (min-width: 768px) and (max-width: 991px) {
  .dashboard {
    padding: 12px;
  }

  .user-card :deep(.el-card__body) {
    padding: 15px;
  }

  .recommendations-card :deep(.el-card__body) {
    padding: 15px;
  }

  .recommendation-card {
    margin-bottom: 15px;
  }
}

/* 移动设备 (最大768px) */
@media (max-width: 768px) {
  .dashboard {
    padding: 10px;
  }

  .user-card,
  .preferences-card,
  .security-card {
    margin-bottom: 15px;
  }

  .user-info {
    text-align: center;
    padding: 15px;
  }

  .avatar-container {
    margin: 0 auto 15px;
  }

  .user-info h2 {
    font-size: clamp(18px, 4vw, 22px);
    margin: 10px 0;
  }

  .user-stats {
    flex-direction: column;
    gap: 15px;
    padding: 15px 0;
  }

  .stat-item {
    width: 100%;
    padding: 12px;
  }

  .recommendations-card :deep(.el-card__body) {
    padding: 15px;
  }

  .recommendation-card {
    margin-bottom: 15px;
  }

  .recommendation-card h3 {
    font-size: clamp(16px, 4vw, 18px);
  }

  .notification-card :deep(.el-card__body) {
    padding: 15px;
  }

  .notification-item {
    padding: 12px;
  }

  .itinerary-card :deep(.el-card__body) {
    padding: 15px;
  }

  .itinerary-item {
    padding: 12px;
    margin-bottom: 10px;
  }

  /* 对话框响应式 */
  .el-dialog {
    width: 95% !important;
    margin: 5vh auto !important;
  }

  .el-dialog__body {
    padding: 15px;
  }
}

/* 小屏移动设备 (最大480px) */
@media (max-width: 480px) {
  .dashboard {
    padding: 8px;
  }

  .user-card :deep(.el-card__header),
  .user-card :deep(.el-card__body),
  .preferences-card :deep(.el-card__header),
  .preferences-card :deep(.el-card__body),
  .security-card :deep(.el-card__header),
  .security-card :deep(.el-card__body) {
    padding: 12px;
  }

  .user-info h2 {
    font-size: 18px;
  }

  .stat-value {
    font-size: 20px;
  }

  .recommendation-card h3 {
    font-size: 16px;
  }

  .notification-item {
    padding: 10px;
  }

  .itinerary-item {
    padding: 10px;
  }

  .el-dialog {
    width: 98% !important;
    margin: 2vh auto !important;
  }

  .el-dialog__body {
    padding: 12px;
  }
}
</style>

